/*
    \file    adxl355.c
    \brief   SPI driver for adxl355
*/
#include "adxl355.h"
#include "gps.h"

RingBuffer *fifo;//AD数据X轴缓冲区
RingBuffer *fifo_x;//AD数据X轴缓冲区
RingBuffer *fifo_y;//AD数据Y轴缓冲区
RingBuffer *fifo_z;//AD数据Z轴缓冲区
#define DUMMY_BYTE 0xA5
#define SET_SPI0_NSS_HIGH gpio_bit_set(GPIOA, GPIO_PIN_4);
#define SET_SPI0_NSS_LOW gpio_bit_reset(GPIOA, GPIO_PIN_4);

rt_event_t adx355_start_event;
void adxl355_rcu_config(void);
void adxl355_gpio_config(void);
void adxl355_spi_config(void);
void adxl355_power_on(void);

// SPI0发送8位的byte,并将读到的8位数据返回
uint8_t SPI0_ReadWriteByte(uint8_t byte)
{
    uint8_t ret_Data;

    while (RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE))
    { //读取"SPI发送缓冲区空"标志
      //等待SPI发送完成
    }

    spi_i2s_data_transmit(SPI0, byte);
    //?byte??"SPI0?????"
    while (RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE))
    { //读取"SPI接收缓冲区非空"标志
      //等待SPI接收完成
    }

    ret_Data = spi_i2s_data_receive(SPI0); //从SPI数据寄存器读数据

    return (ret_Data);
}
//函数功能:SPI0发送byte,并将读到的数据返回
uint8_t spi_adxl_send_byte(uint8_t byte)
{
    uint8_t ret_Data;

    ret_Data = SPI0_ReadWriteByte(byte);

    return (ret_Data);
}

//函数功能:SPI0发送DUMMY_BYTE,为的是读取数据,并返回读到的值
uint8_t spi_flash_read_byte(void)
{
    uint8_t ret_Data;

    ret_Data = SPI0_ReadWriteByte(DUMMY_BYTE);
    // SPI0?接受一个byte,并将数据返回
    return (ret_Data);
}
uint32_t adxl355_spi_reg_write(int addr, rt_uint8_t value)
{
    rt_uint8_t reg;
    reg = ((addr << 1) | ADXL355_SPI_WRITE); // spi 写的寄存器地址

    SET_SPI0_NSS_LOW //片选选中

        spi_adxl_send_byte(reg);

    spi_adxl_send_byte(value);

    SET_SPI0_NSS_HIGH
		
		return RT_EOK;
}
uint32_t adxl355_spi_reg_read(int base_address, uint8_t *read_data, uint16_t size)
{
    rt_uint8_t i;
    rt_uint8_t reg;                                 // spi地址
    reg = ((base_address << 1) | ADXL355_SPI_READ); // spi 读取的寄存器地址
    SET_SPI0_NSS_LOW

    spi_adxl_send_byte(reg); //读ID寄存器

    for (i = 0; i < size; i++)
    {
        read_data[i] = spi_adxl_send_byte(DUMMY_BYTE);
    }

    SET_SPI0_NSS_HIGH

    return RT_EOK;
}
/***************************************************************************//**
 * @brief Converts array of raw acceleration to uint32 data raw acceleration
 *
 * @param dev       - The device structure.
 * @param raw_array - Raw acceleration array.
 *
 * @return ret      - Converted data.
*******************************************************************************/
static uint32_t adxl355_accel_array_conv(uint8_t *raw_array)
{
    uint32_t raw_accel;

    // raw_array[0] bits [7-0]: DATA bits [19:12]
    // raw_array[1] bits [7-0]: DATA bits [11: 4]
    // raw_array[2] bits [7-4]: DATA bits [ 3: 0]
    // raw_array[2] bits i[3-0]: reserved
    raw_accel = no_os_get_unaligned_be24(raw_array);

    return (raw_accel >> 4);
}
/***************************************************************************/ 
/**
* @brief Reads the number of FIFO entries register value.
*
* @param reg_value - Register value.
*
* @return
*******************************************************************************/
void adxl355_get_nb_of_fifo_entries(uint8_t *reg_value)
{
    adxl355_spi_reg_read(ADXL355_FIFO_ENTRIES, reg_value, 1);
}
/****************************************************************************************
 *@brief   adxl355加速度FIFO原始值获取
 *@param[in]@return count
 *****************************************************************************************/
uint8_t adxl355_get_raw_fifo_data(uint8_t *read_data, uint32_t *raw_x, uint32_t *raw_y, uint32_t *raw_z)
{
    uint8_t count = 0;
    uint8_t remain_count = 0;
    uint8_t fifo_entries;
    uint32_t delay;
    uint16_t idx;

    adxl355_get_nb_of_fifo_entries(&fifo_entries);
    remain_count = fifo_entries % 3;
    count = fifo_entries;
    if (remain_count != 0)
    {
        for (delay = 1080; delay > 0; delay--)
            __NOP();
        count = fifo_entries + (3 - remain_count);
    }

    if (count > 0)
    {
        adxl355_spi_reg_read(ADXL355_FIFO_DATA, read_data, count * 3);
        for (idx = 0; idx < count * 3; idx = idx + 9)
        {
            if (((read_data[idx + 2] & 1) == 1) && ((read_data[idx + 2] & 2) == 0))
            {
                // This is x-axis
                raw_x[idx / 9] = adxl355_accel_array_conv(&read_data[idx]);
                raw_y[idx / 9] = adxl355_accel_array_conv(&read_data[idx + 3]);
                raw_z[idx / 9] = adxl355_accel_array_conv(&read_data[idx + 6]);
            }
        }
    }

    return count;
}
int accel_ringbuffer_init(void)
{
//	fifo_x = RingBuffer_Malloc(4096);
//	if(fifo_x != NULL)
//  {
//    rt_kprintf("X_FIFO创建成功，FIFO大小：%d，使用大小：%d，剩余大小：%d\n",
//		RingBuffer_Size(fifo_x), RingBuffer_Len(fifo_x), RingBuffer_Avail(fifo_x));
//	}
//	fifo_y = RingBuffer_Malloc(4096);
//		if(fifo_x != NULL)
//  {
//    rt_kprintf("Y_FIFO创建成功，FIFO大小：%d，使用大小：%d，剩余大小：%d\n",
//		RingBuffer_Size(fifo_x), RingBuffer_Len(fifo_x), RingBuffer_Avail(fifo_x));
//	}
//	fifo_z = RingBuffer_Malloc(4096);
//	if(fifo_x != NULL)
//  {
//		rt_kprintf("Z_FIFO创建成功，FIFO大小：%d，使用大小：%d，剩余大小：%d\n",
//		RingBuffer_Size(fifo_x), RingBuffer_Len(fifo_x), RingBuffer_Avail(fifo_x));
//	}
	fifo = RingBuffer_Malloc(4096*4);
	if(fifo != NULL)
  {
    rt_kprintf("X_FIFO创建成功，FIFO大小：%d，使用大小：%d，剩余大小：%d\n",
		RingBuffer_Size(fifo), RingBuffer_Len(fifo), RingBuffer_Avail(fifo));
	}
}
/*!
    \brief      main function
    \param[in]  none
    \param[out] none
    \retval     none
*/
int adxl355_hw_init(void)
{
    rt_uint8_t id[4] = {0};
    /* peripheral clock enable */
    adxl355_rcu_config();
    /* GPIO configure */
    adxl355_gpio_config();
    /* SPI configure */
    adxl355_spi_config();
    /* SPI enable */
    spi_enable(SPI0);

    /* wait for transmit complete */
    adxl355_power_on();
    /* reset after power on */
    adx355_start_event = rt_event_create("adx355_start_event", RT_IPC_FLAG_PRIO);
    if (adx355_start_event == NULL)
    {
        rt_kprintf("adx355_start_event create failed!\n");
        return -RT_ERROR;
    }
		accel_ringbuffer_init();
		rt_thread_mdelay(100);
    adxl355_spi_reg_read(ADXL355_DEVID_AD, id, 4);
    rt_kprintf("IDs %x %x %x %x!\n", id[0], id[1], id[2], id[3]);
    adxl355_spi_reg_write(ADXL355_RESET, ADXL355_RESET_CODE);
    rt_thread_mdelay(100);

    //配置传感器工作模式
    rt_kprintf("prepare to set EXT_SYNC register to 01\n");
    uint8_t EXT_SYNC = 0;
    adxl355_spi_reg_read(ADXL355_SYNC, &EXT_SYNC, 1);
    rt_kprintf("EXT_SYNC register now is:[%d]\n", EXT_SYNC);
    rt_kprintf("writing register...\n");
    CLEAR_BIT(EXT_SYNC, 1 << 0);
    SET_BIT(EXT_SYNC, 1 << 0 | 1 << 2);
    adxl355_spi_reg_write(ADXL355_SYNC, EXT_SYNC);
    adxl355_spi_reg_read(ADXL355_SYNC, &EXT_SYNC, 1);
    rt_kprintf("EXT_SYNC register now is:[%d]\n", EXT_SYNC);
    uint8_t RANGE;
    adxl355_spi_reg_read(ADXL355_RANGE, &RANGE, 1);
    rt_kprintf("INTPOL:RANGE register now is:[%d]\n", RANGE);
    uint8_t INT;
    adxl355_spi_reg_read(ADXL355_INT_MAP, &INT, 1);
    rt_kprintf("ADXL355_INT_MAP:INT register now is:[%d]\n", INT);
    SET_BIT(INT, 1 << 2);
    adxl355_spi_reg_write(ADXL355_INT_MAP, INT);
    rt_kprintf("writing register...\n");
    rt_kprintf("ADXL355_INT_MAP:INT register now is:[%d]\n", INT);
    rt_uint32_t e;
    rt_event_recv(adx355_start_event, _ADX355_START_EVENT, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
                  RT_WAITING_FOREVER, &e);
    rt_kprintf("gps ready start sample...\r\n");

    struct tm time;
    time = get_gps_time();
    rt_kprintf("gps sync time %d-%d-%d:%d:%d:%d:\n",
               time.tm_year, time.tm_mon, time.tm_mday,
               time.tm_hour, time.tm_min, time.tm_sec);
    //设置电源控制寄存器STANDBY的值：1为待机模式，0为测量模式
    rt_kprintf("prepare to set POWER_CTL:STANDBY register to 0\n");
    uint8_t STANDBY;
    adxl355_spi_reg_read(ADXL355_POWER_CTL, &STANDBY, 1);
    rt_kprintf("POWER_CTL:STANDBY register now is:[%d]\n", STANDBY);
    rt_kprintf("writing register...\n");
    CLEAR_BIT(STANDBY, 1 << 0);
    adxl355_spi_reg_write(ADXL355_POWER_CTL, STANDBY);

    adxl355_spi_reg_read(ADXL355_POWER_CTL, &STANDBY, 1);
    rt_kprintf("POWER_CTL:STANDBY register now is:[%d]\n", STANDBY);

    return RT_EOK;
}

/*!
    \brief      configure different peripheral clocks
    \param[in]  none
    \param[out] none
    \retval     none
*/
void adxl355_rcu_config(void)
{
    rcu_periph_clock_enable(RCU_GPIOA); // spi gpio
    rcu_periph_clock_enable(RCU_SPI0);
    rcu_periph_clock_enable(RCU_GPIOD); // sensor enable gpio :PD3
    rcu_periph_clock_enable(RCU_AF);
}

/*!
    \brief      configure the GPIO peripheral
    \param[in]  none
    \param[out] none
    \retval     none
*/
void adxl355_gpio_config(void)
{
    /* SPI0 GPIO config:SCK/PA5, MISO/PA6, MOSI/PA7 */
    gpio_pin_remap_config(GPIO_SPI0_REMAP, DISABLE);
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_7);
    gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
    gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);
    gpio_init(GPIOD, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3); // PD3
    gpio_init(GPIOC, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_11);

    SET_SPI0_NSS_HIGH; // PA4 set
}

/*!
    \brief      configure the SPI peripheral
    \param[in]  none
    \param[out] none
    \retval     none
*/
void adxl355_spi_config(void)
{
    spi_parameter_struct spi_init_struct;
    /* deinitilize SPI and the parameters */
    spi_i2s_deinit(SPI0);
    spi_struct_para_init(&spi_init_struct);

    /* SPI0 parameter config */
    spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.device_mode = SPI_MASTER;
    spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE; // SPI MODE0
    spi_init_struct.nss = SPI_NSS_SOFT;
    spi_init_struct.prescale = SPI_PSC_8;
    spi_init_struct.endian = SPI_ENDIAN_MSB;
    spi_init(SPI0, &spi_init_struct);
}
void adxl355_power_on(void)
{
    gpio_bit_reset(GPIOD, GPIO_PIN_3);
}
// INIT_APP_EXPORT(adxl355_hw_init);
MSH_CMD_EXPORT(adxl355_hw_init, adxl355 test); /*  INIT_BOARD_EXPORT */
